#include "ThreadPeersConectar.h"
#include "Torrent.h"


ThreadPeersConectar::ThreadPeersConectar(Torrent *torrent, unsigned int maxCantPeers) {

	this->torrent = torrent;

	this->maxCantPeers = maxCantPeers;
}

ThreadPeersConectar::~ThreadPeersConectar() {


}

void* ThreadPeersConectar::run() {

	while((!this->getStop())) {

		this->torrent->conditionPeersPorConectar.mutexLock();

		if(this->torrent->colaPeersPorConectar.empty()){
			this->torrent->conditionPeersPorConectar.wait();
		}

		cout << "size cola :" << this->torrent->colaPeersPorConectar.size()<< endl;

		if(this->getStop()){
			this->torrent->conditionPeersPorConectar.mutexUnlock();
			return NULL;
		}

		Peer nuevoPeer = this->torrent->colaPeersPorConectar.front();

		this->torrent->conditionPeersConectados.mutexLock();
		unsigned int peersSize = this->torrent->listaPeerConectados.size();
		this->torrent->conditionPeersConectados.mutexUnlock();

		this->torrent->colaPeersPorConectar.pop();
		this->torrent->conditionPeersPorConectar.mutexUnlock();

		if (peersSize < this->getMaxCantPeers()) {
			this->conectarPeer(nuevoPeer);
		}
	}
	return NULL;
}


void ThreadPeersConectar::conectarPeer(Peer peer) {

	this->torrent->conditionPeersConectados.mutexLock();

	list<InterfazPeer*>::iterator it = this->torrent->listaPeerConectados.begin();
	bool encontrado = false;
	bool error;

	/* Primero se verifica que no exista un Peer con la misma configuracion ip/puerto */

	while ((!encontrado) && (it != this->torrent->listaPeerConectados.end())) {
		InterfazPeer* peerActual = *it;

		if ((peer.ip == peerActual->getServer()) && (peer.puerto = peerActual->getPuerto())) {
			encontrado = true;
		}
		it++;
	}

	/* Si no se encontro un Peer con la misma configuracion, se realiza la conexion con el Peer
	 * para detectar su id */
	if (!encontrado) {
		string peerId;
		ConexionPeerCliente* conexionPeer = new ConexionPeerCliente(this->torrent->info->getHashInfo(), this->torrent->idCliente);
		this->torrent->conditionPeersConectados.mutexUnlock();
		error = !conexionPeer->conectar(peer.ip,peer.puerto);
		this->torrent->conditionPeersConectados.mutexLock();

		if (!error) {
			error = !conexionPeer->bidireccionalHandshake(peerId);
			if (!error) {
				it = this->torrent->listaPeerConectados.begin();
				while ((!encontrado) && (it != this->torrent->listaPeerConectados.end())) {
					InterfazPeer* peerActual = *it;
					if (peerActual->getPeerId() == peerId) {
						encontrado = true;
					}
					it++;
				}
				if (!encontrado) {
					InterfazPeer* nuevoPeer = new InterfazPeer(conexionPeer, peerId, this->torrent->info->getCantidadPiezas(), &this->torrent->conditionError, &this->torrent->mutexPiezas, &this->torrent->piezas, &this->torrent->mutexPiezasABajarOBajadas, &this->torrent->piezasPorBajar, &this->torrent->piezasBajadas, peer.ip, peer.puerto);

					this->torrent->listaPeerConectados.push_back(nuevoPeer);
					cout << "se acolo el peer " << peerId << endl;
					cout << " Se encuentran acolados un total de " << this->torrent->listaPeerConectados.size()<< " peers " << endl;
				} else {
					conexionPeer->shutdownAndClose();
				}
			}
		}
	}
	this->torrent->conditionPeersConectados.mutexUnlock();

}

void ThreadPeersConectar::stop() {
	//TODO hacer el stop.
}

void ThreadPeersConectar::setMaxCantPeers(unsigned int maxCantPeers) {

	this->mutexMaxCantPeers.lock();
	this->maxCantPeers = maxCantPeers;
	this->mutexMaxCantPeers.unlock();
}

unsigned int ThreadPeersConectar::getMaxCantPeers() {

	unsigned int aux;

	this->mutexMaxCantPeers.lock();
	aux = maxCantPeers;
	this->mutexMaxCantPeers.unlock();

	return aux;
}

